通信制御用APIを使ったシリアル通信プログラム開発
API関数
API(Application Programming Interface)関数は、Windows自体が持っている機能です。Windows上で動作するアプリケーションであれば、共通して使うことができます。DLL(Dinamic
Link Library)ファイルで提供されています。API関数の数は、数百種あって、Windowsの主たる機能が納められています。Visual
Basicは、たくさんの命令を持ってはいますが、すべてのWindows機能を網羅しているわけではなく、Visual
Basicの命令で実行できないものは、直接API関数を呼び出して利用することになります。初めてAPI関数を活用する読者にとっては、何やら難しいというイメージを持つかもしれませんが、便利なプロシージャの一つと思ってください。「Declare」宣言文で定義するだけで、他のプロシージャと同じように利用することができます。API関数に慣れてしまえば、Visual
BasicでほとんどのWindowsプログラミングが可能になります。シリアル通信ですが、CreateFile(API関数)でポートをオープンし、WriteFile/ReadeFile(API関数)でデータを送受し、CloseHandle(API関数)でクローズするというようにAPI関数を使っていきます。
APIビューアの利用の仕方
Visual Basicには、APIビューアというDeclare文や構造体の内容、定数の値を簡単に取り込めるソフトがありますので、まずはその使い方をマスターしましょう。ここでは、シリアルポート関連のAPI関数として、「CreateFile関数」の例を用いて説明します。手順は次の通りです。
![]() |
図1.APIビューアの使い方 |
Visual Basicの標準モジュールを追加して、その宣言領域にDeclare文をペーストすれば、Visual
BasicでAPI関数が利用できるようになります。
また、構造体については、
なお、API関数の宣言文をテキスト化して集めた「Win32Api.TXT」のファイルは、
Program Files \ DevStudio \ Vb \ Winapi のディレクトリの下に置かれています。
API関数の利用の仕方
API関数やDLLに含まれるプロシージャを利用するためには、Declare宣言文として記述することで利用できます。宣言文には、DLLに含まれているプロシージャ名(API関数名)と、引数のタイプを記述します。記述場所は、標準モジュール宣言領域(GeneralのDeclarations)か、フォームモジュール宣言領域になります。標準モジュールに記述した場合には、どのモジュールからでも利用することができますが、フォームモジュールに記述した場合には、そのモジュール内だけしか有効になりませんので、「Private」をDeclareの前につける必要があります。したがって、APIビューアでそのままコピーして張り付けるような場合には、標準モジュール内で宣言しておく方が簡単です。なお、標準モジュール内で宣言するといっても、宣言領域を使うだけであり、プログラムを標準モジュールからスタートさせる必要はありません。
宣言文のタイプは、「Function」タイプと、「Sub」タイプの2種類がありますが、API関数のほとんどは「Function」タイプを使います。タイプの違いですが、「Function」は戻り値があるのに対して、「Sub」は戻り値がありません。
宣言文の内容は、プロシージャ名、DLLファイル名、引数のタイプです。プロシージャ名は、「Alias」を使ってDLL内での名称とは別にすることがあります。これは、Visual
Basicでは許されない記述方法として、_で始まるプロシージャがあった場合に、Visual
Basicで呼び出し可能なプロシージャ名に変更しています。API関数においては、「ByVal」で引数を渡すことが多いです。「ByVal」指定をすると値渡しとなります。
●API関数(DLL内プロシージャ)のDeclare宣言文の一般形式
Declare Function プロシージャ名(API関数) Lib "DLLファイル名" [Alias"DLL内でのプロシージャ名"]
(引数1,引数2,・・・) As Type
●実行文の一般形式
dummy = プロシージャ名(API関数) (引数1,引数2,・・・)
それでは、次にシリアル通信に関連する主なAPI関数を解説していきましょう。
シリアルポートのオープン(CreateFile関数)について
シリアルポートを利用するときには、ファイルと同じ手続きをします。ファイルをオープンするようにポートをオープンします。API関数は、CreateFile関数になります。
Win32Api.TXTの内容(CreateFile関数)は、以下のようになっています。
Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As SECURITY_ATTRIBUTES, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
●CreateFile関数の実行文
戻り値=CreateFile ( [1] ファイル名, [2] オープン方法, [3] 共有モード, [4] セキュリティ属性, [5] 既存ファイルの処理, [6] ファイルの属性, [7] テンプレートファイル )
戻り値は、成功すればハンドル値、失敗すれば「−1」を返します。
なお、CreateFile関数の引数についての設定は、表1を参照してください。
引数(パラメータ) | 型(変数定義) | 意味 | 設定のポイント | |
[1] | lpFileName | String | ファイル名 | "COM1","COM2"など 本リストでは"COM1"を指定 |
[2] | dwDesiredAccess | Long | オープン方法 | 読み書き両用にする 「&H80000000 OR &H40000000」 |
[3] | dwShareMode | Long | 共有モード | 共有しない「0」 |
[4] | lpSecurityAttributes | SECURITY_ATTRIBUTES →Longに変更する |
セキュリティ属性 | 使用しない 宣言文の型を変更して「0」 |
[5] | dwCreationDisposition | Long | 既存ファイルの処理 | 既存のファイルをオープン 「&H3」を指定する |
[6] | dwFlagsAndAttributes | Long | ファイルの属性 | なし「0」 |
[7] | hTemplateFile | Long | テンプレートファイル | 使わない「0」 |
CreateFile関数は、そのままでは構造体を含む形になっているので、4番目のパラメータの変数定義「SECURITY_ATTRIBUTES」を「Long」に変更します。また、引数の先頭に「ByVal」も付けておいてください。これで、この部分の設定は「0」を与えるだけでよくなります。
シリアルポートのクローズ(CloseHandle関数)について
シリアルポートに関する操作を行った後には、ポートをクローズします。API関数は、CloseHandle関数になります。
Win32Api.TXTの内容(CloseHandle関数)は、以下のようになっています。引数は、クローズするハンドルを渡すだけです。
Declare Function CloseHandle Lib "kernel32" Alias "CloseHandle" (ByVal hObject As Long) As Long
●CloseHandle関数の実行文
戻り値 = CloseHandle ( ポートのハンドル )
戻り値は、成功すれば「0」、失敗すればハンドルをそのまま返す。
●プログラム開発上での注意点
ポートをオープンした後に、何らかの理由でエラーになったりすると、ポートはオープンのままになってしまいます。オープンのままですと、次に開こうとしてもオープンできません。一番簡単な対処法は、ポートが開けなくなったら、いったんVisual
Basicを終了するとクローズします。開発中はよく起きるトラブルですので、オープン後にハンドル番号をフォームなどに表示させてその番号を確認し、その番号をもとにオープン前にクローズしておくようにすると回避できます。ハンドル値は、Visual
Basic起動後は一定の値になりますが、起動するたびに変化しますので注意してください。
シリアルポートの設定(SetCommState関数)について
ポートをオープンした後、伝送方法を設定します。API関数は、SetCommState関数になります。パラメータとしてハンドルとDCB構造体が必要になります。DCB構造体では、必要な伝送方法のほとんどを設定することができます。Win32Api.TXTの内容(SetCommState関数)は、以下のようになっています。
Declare Function SetCommState Lib "kernel32" Alias "SetCommState" (ByVal hCommDev As Long, lpDCB As DCB) As Long
●SetCommState関数の実行文
戻り値 = SetCommState ( ポートのハンドル, DCB構造体 )
なお、DCB構造体のメンバについては、表2を参照してください。
シリアルポートの状態取得(GetCommState関数)について
ポートの状態を取得するAPI関数は、GetCommState関数になります。パラメータとしてハンドルとDCB構造体が必要になります。Win32Api.TXTの内容(GetCommState関数)は、以下のようになっています。
Declare Function GetCommState Lib "kernel32" Alias "GetCommState" (ByVal nCid As Long, lpDCB As DCB) As Long
●GetCommState関数の実行文
戻り値 = GetCommState ( ポートのハンドル, DCB構造体 )
なお、DCB構造体のメンバについては、表2を参照してください。
メンバ | 型 | 意味 |
DCBlength | Long | 構造体のサイズ |
BaudRate | Long | ボーレート(bps)の設定・・・直接値を代入する。 例:110, 150, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400 |
fBitFields | Long | 表3を参照 |
wReserved | Integer | 予約(0をセットする) |
XonLim | Integer | 受信バッファ中のデータが何バイトになったら Xon文字を送るかを指定 |
XoffLim | Integer | 受信バッファの空きが何バイトになったら Xoff文字を送るかを指定 |
ByteSize | Byte | 1データのビット数を指定・・・7または8 |
Parity | Byte | パリティの方式を指定 0・・・NOPARITY (パリティなし) 1・・・ODDPARITY (奇数パリティ) 2・・・EVENPARITY (偶数パリティ) 3・・・MARKPARITY (常にマーク) |
StopBits | Byte | ストップビット数を指定 0・・・ONESTOPBIT (1ビット) 1・・・ONE5STOPBITS (1.5ビット) 2・・・TOSTOPBITS (2ビット) |
XonChar | Byte | Xon文字を指定 |
XoffChar | Byte | xoff文字を指定 |
ErrorChar | Byte | パリティエラーの場合に使う文字を指定 |
EofChar | Byte | 非バイナリモードの場合のデータ終了文字の指定 |
EvtChar | Byte | イベントを生成する文字を指定 |
wReserved1 | Integer | (未使用) |
ビット | フィールド名 | 意味 |
1 | fBinary | バイナリモードかどうか |
2 | fParity | パリティチェックの有無 |
3 | fOutxCtsFlow | CTSを監視するかどうか |
4 | fOutxDsrFlow | DSRを監視するかどうか |
5,6 | fDtrControl | DTRによるハンドシェーク(2ビット) |
7 | fDsrSensitivity | TrueのときDSRがオフのときの受信データを無視する |
8 | fTXContinueOnXoff | Xoff文字を送信した後も送信を続けるかどうか |
9 | fOutX | TrueのときXoff文字を受信すると送信を停止し、 Xon文字で再開 |
10 | fInX | Trueのとき受信バッファの空きに応じて Xoff、Xon文字が送信される |
11 | fErrorChar | Trueのときパリティエラーの処理をする |
12 | fNull | Trueのときヌル文字は破棄される |
13,14 | fRtsControl | RTSによるハンドシェーク(2ビット) |
15 | fAbortOnError | Trueのときエラーが発生したら読み書きを終了する |
16 | fDummy2 | 未使用 |
(注意)Visual Basic バージョン4.0のAPIビューアで取得したDCBの内容についてはバグがあります。ビット単位でまとめてfBitFieldsとして定義されるべきところを、フィールド(表3)を個々にLong型で定義されてしまっています。
タイムアウトの設定(SetCommTimeouts関数)について
外付け装置に異常があるため、データが受け取れずハングアップのような状態に陥ってしまうことがよくあります。このようなことを回避するために、タイムアウトの時間を設定します。API関数は、SetCommTimeouts関数になります。パラメータとしてハンドルとCOMMTIMEOUTS構造体が必要になります。Win32Api.TXTの内容(SetCommTimeouts関数)は、以下のようになっています。
Declare Function SetCommTimeouts Lib "kernel32" Alias "SetCommTimeouts" (ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) As Long
●SetCommTimeouts関数の実行文
戻り値 = SetCommTimeouts ( ポートのハンドル, COMMTIMEOUTS構造体 )
なお、COMMTIMEOUTS構造体のメンバについては、表4を参照してください。
タイムアウトの状態取得(GetCommTimeouts関数)について
API関数は、GetCommTimeouts関数になります。タイムアウトの設定の状態を確認することができます。パラメータとしてハンドルとCOMMTIMEOUTS構造体が必要になります。Win32Api.TXTの内容(GetCommTimeouts関数)は、以下のようになっています。
Declare Function GetCommTimeouts Lib "kernel32" Alias "GetCommTimeouts" (ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) As Long
●GetCommTimeouts関数の実行文
戻り値 = GetCommTimeouts ( ポートのハンドル, COMMTIMEOUTS構造体 )
なお、COMMTIMEOUTS構造体のメンバについては、表4を参照してください。
メンバ | 型 | 意味 |
ReadIntervalTimeout | Long | 文字の読み込みの待ち時間 |
ReadTotalTimeoutMultiplier | Long | 読み込みの1文字あたりの時間 |
ReadTotalTimeoutConstant | Long | 読み込みの定数時間 |
WriteTotalTimeoutMultiplier | Long | 書き込みの1文字あたりの時間 |
WriteTotalTimeoutConstant | Long | 書き込みの定数時間 |
1番目(ReadIntervalTimeout)が、読み込みの待ち時間です。また、2番目以降のメンバを使って、トータルの時間も設定できます。たとえば、100文字読み込む場合には、1文字あたりの時間(2番目)×100+定数時間(3番目)がトータル時間となり、これを越えると処理が中止されます。
データの送信(WriteFile関数)について
データを送信するAPI関数は、WriteFile関数になります。Win32Api.TXTの内容(WriteFile関数)は、以下のようになっています。
Declare Function WriteFile Lib "kernel32" Alias "WriteFile"
(ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long,
lpNumberOfBytesWritten As Long, lpOverlapped As OVERLAPPED) As Long
●WriteFile関数の実行文
戻り値 = WriteFile ( ポートのハンドル, 送信データ, 送信したい数, 送信した数, 0 )
戻り値は、成功すれば「1」、失敗すれば「0」
2番目のパラメータは、送信するデータであり、「Any」なので文字列でも、数値でも可能です。ただし、文字列もしくはバイト配列の場合には固定長にしておく必要があります。また文字変数を使う場合には、文字変数は変数名を指定しても実際に文字が格納されているポインタを引き渡すことができませんので、必ず「ByVal」をつけてください。怠ると保護違反になります。宣言文には、「ByVal」がついていないので実行文の方につけておきます。3番目のパラメータでは、送信したいバイト数を厳密に指定してください。4番目のパラメータは、実際にやりとりしたバイト数が格納されます。宣言文の中には、5番目のパラメータにOVERLAPPED構造体が入っていますが、今回の用途では使用しないので、Long型に変更しておきます。実行文では ByVal
0& を与えます(単なる0でもよい)。
データの受信(ReadFile関数)について
データを受信するAPI関数は、ReadFile関数になります。Win32Api.TXTの内容(ReadFile関数)は、以下のようになっています。
Declare Function ReadFile Lib "kernel32" Alias "ReadFile" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As OVERLAPPED) As Long
●ReadFile関数の実行文
戻り値 = ReadFile ( ポートのハンドル, 受信データ, 受信したい数, 受信した数, 0 )
戻り値は、成功すれば「1」、失敗すれば「0」
2番目のパラメータは、受信するデータであり、「Any」なので文字列でも、数値でも可能です。ただし、文字列もしくはバイト配列の場合には固定長にしておく必要があります。また文字変数を使う場合には、文字変数は変数名を指定しても実際に文字が格納されているポインタを引き渡すことができませんので、必ず「ByVal」をつけてください。怠ると保護違反になります。宣言文には、「ByVal」がついていないので実行文の方につけておきます。3番目のパラメータでは、受信したいバイト数を「100バイト」などのように大きめに指定しておきます。4番目のパラメータで、実際にやりとりしたバイト数がわかりますので、後から必要な文だけ取り出します。宣言文の中には、5番目のパラメータにOVERLAPPED構造体が入っていますが、今回の用途では使用しないので、Long型に変更しておきます。実行文では ByVal
0& を与えます(単なる0でもよい)。
シリアルポートの機能調査(GetCommProperties関数)について
ポートの機能を調べるAPI関数は、GetCommProperties関数になります。パラメータとしてハンドルとCOMMPROP構造体が必要になります。Win32Api.TXTの内容(GetCommProperties関数)は、以下のようになっています
Declare Function GetCommProperties Lib "kernel32" Alias "GetCommProperties"
(ByVal hFile As Long, lpCommProp As COMMPROP) As Long
●GetCommProperties関数の実行文
戻り値 = GetCommProperties ( ポートのハンドル, COMMPROP構造体 )
なお、COMMPROP構造体のメンバについては、表5を参照してください。
メンバ | 型 | 意味 |
wPacketLength | Integer | 構造体のサイズ |
wPacketVersion | Integer | 構造体のバージョン |
dwServiceMask | Long | 実装されているサービス |
dwReserved1 | Long | 予約 |
dwMaxTxQueue | Long | 最大送信バッファサイズ |
dwMaxRxQueue | Long | 最大受信バッファサイズ |
dwMaxBaud | Long | 最大ボーレート |
dwProvSubType | Long | デバイスの種類 |
dwProvCapabilities | Long | サポートされている機能 |
dwSettableParams | Long | 変更可能なパラメータ |
dwSettableBaud | Long | 許されるボーレート |
wSettableData | Integer | 許されるバイトサイズ |
wSettableStopParity | Integer | 許されるストップビット/パリティの設定 |
dwCurrentTxQueue | Long | 送信バッファサイズ |
dwCurrentRxQueue | Long | 受信バッファサイズ |
dwProvSpec1 | Long | プロバイダ用 |
dwProvSpec2 | Long | |
wcProvChar(1) | Integer |
サポートされている機能は、COMMPROPの「dwProvCapabilities」メンバと、表6のフラグを用いて知ることができます。
たとえば、DTR/DSRの機能は、メンバの1ビット目に記されていますので、&H1&と論理和をとれば知ることができます。ほとんどのパソコンは、16ビットの特殊なデータモード以外はすべてサポートしていると思います。
定数 | 値 | サポートされている機能 |
PCF_DTRDSR | &H1& | DTR/DSR機能 |
PCF_RTSCTS | &H2& | RTS/CTS機能 |
PCF_RLSD | &H4& | CD機能 |
PCF_PARITY_CHECK | &H8& | パリティチェック |
PCF_XONXOFF | &H10& | XON/XOFFのフロー制御 |
PCF_SETXCHAR | &H20& | XON/XOFF機能の設定 |
PCF_TOTALTIMEOUTS | &H40& | 経過時間のタイムアウト |
PCF_INTTIMEOUTS | &H80& | インターバルタイムアウト |
PCF_SPECIALCHARS | &H100& | 特殊文字 |
PCF_16BITMODE | &H200& | 16ビットのデータモード |
シリアルポート制御信号の直接操作(EscapeCommFunction関数)について
Windowsの場合は、直接ハードウェアを制御することは制限されていますが、シリアルポートの制御信号線の場合には専用のAPI関数としてEscapeCommFunction関数があります。出力のDTR,RTS端子の場合には、シリアルポートをオープンした後に、フラグとして表7の値を与えることで直接制御することができます。たとえば、DTR端子をオンにするときには、「5」を与えます。Win32Api.TXTの内容(EscapeCommFunction関数)は、以下のようになっています
Declare Function EscapeCommFunction Lib "kernel32" Alias "EscapeCommFunction" (ByVal nCid As Long, ByVal nFunc As Long) As Long
●EscapeCommFunction関数の実行文
戻り値 = EscapeCommFunction ( ポートのハンドル, フラグ )
フラグの定数 | 値 | サポートされている機能 |
SETRTS | 3 | RTSをオンにする |
CLRRTS | 4 | RTSをオフにする |
SETDTR | 5 | DTRをオンにする |
CLRDTR | 6 | DTRをオフにする |
SETXOFF | 1 | XOFFを受信したときの処理 |
SETXON | 2 | XONを受信したときの処理 |
SETBREAK | 8 | 送信をブレーク状態にする |
CLRBREAK | 9 | 送信のブレーク状態から復帰 |
シリアルポートの入力制御信号の状態監視(GetCommModemStatus関数)について
シリアルポートの入力制御信号の状態監視として、DSR,CTS端子の場合には、GetCommModemStatus関数があります。パラメータから得た値に対して、表8のマスクをかけて状態を知ります。たとえば、DSR端子の場合には、&h20&と論理和をとり、0以外であればオン、0であればオフということになります。Win32Api.TXTの内容(GetCommModemStatus関数)は、以下のようになっています
Declare Function GetCommModemStatus Lib "kernel32" Alias "GetCommModemStatus"
(ByVal hFile As Long, lpModemStat As Long) As Long
●GetCommModemStatus関数の実行文
戻り値 = GetCommModemStatus ( ポートのハンドル, マスク値 )
マスクの定数 | 値 | 内容 |
MS_CRT_ON | &H10& | CTSがオン |
MS_DSR_ON | &H20& | DSRがオン |
MS_RING_ON | &H40& | リングがオン |
MS_RLSD_ON | &H80& | RLSD(CD)がオン |
次へは、Visual Basicプログラムの作成手順について解説していきます。
![]() |
![]() |
![]() |